﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

using FanaticToy.Core.Configure;

namespace FanaticToy.Core
{
    public class NodePair
    {
        public string Name { get; set; }
        public string FullPath { get; set; }

        public NodePair()
        {

        }

        public NodePair(string name, string fullPath)
        {
            Name = name;
            FullPath = fullPath;
        }
    }

    ///<summary>目录管理对象。</summary>
    public class DirectoryManager
    {
        #region fields

        private string _slnPath, _slnDir;
        private Configure.ToyConfiguration _config;

        private List<NodePair> _sortedNodePairs;

        #endregion

        #region props

        ///<summary>原始的配置信息。</summary>
        public Configure.ToyConfiguration Configuration => _config;

        #endregion

        #region ctors

        public DirectoryManager(string slnPath, ToyConfiguration config)
        {
            CheckSln(slnPath);
            _slnPath = slnPath;
            _slnDir = Path.GetDirectoryName(slnPath);
            _config = config;

            if (config == null) throw new NullReferenceException("DirectoryManager.ctor: 无法找到 ToyConfiguration 实例");

            _sortedNodePairs = config
                .Nodes
                .OrderByDescending(n => n.ReleativePath)
                .Select(n => new NodePair(n.Name, Path.Combine(_slnDir, n.ReleativePath)))
                .ToList();
        }

        public DirectoryManager(string slnPath) : this(slnPath, GetToyConfiguration(GetToyConfigurationFilePath(slnPath)))
        {

        }

        ///<summary>获得配置文件的路径。</summary>
        private static string GetToyConfigurationFilePath(string slnPath)
        {
            var slnDir = Path.GetDirectoryName(slnPath);
            return Path.Combine(slnDir, ".fantoy", "config.xml");
        }

        ///<summary>获得文件的配置信息。</summary>
        private static Configure.ToyConfiguration GetToyConfiguration(string path)
        {
            if (string.IsNullOrWhiteSpace(path)) return null;

            var seri = new XmlSerializer(typeof(Configure.ToyConfiguration));
            using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
            {
                return seri.Deserialize(fs) as Configure.ToyConfiguration;
            }
        }

        #endregion

        #region methods

        public CodeMetaData GetCodeMetaData(string nodeId, string fileId, string member)
        {
            return GetCodeMetaDatas(new IdentifierStrategy.LocationIdentifier(nodeId, fileId, member)).FirstOrDefault();
        }

        public CodeMetaData[] GetCodeMetaDatas(string nodeId, string fileId, string member)
        {
            return GetCodeMetaDatas(new IdentifierStrategy.LocationIdentifier(nodeId, fileId, member));
        }

        public CodeMetaData GetCodeMetaData(IdentifierStrategy.LocationIdentifier identifier)
        {
            return GetCodeMetaDatas(identifier).FirstOrDefault();
        }

        ///<summary>获得符合要求的MetaData</summary>
        public CodeMetaData[] GetCodeMetaDatas(IdentifierStrategy.LocationIdentifier identifier)
        {
            var resultList = new List<CodeMetaData>();

            var name = identifier.NodeId;
            var node = _config.Nodes.FirstOrDefault(n => string.Equals(n.Name, name, StringComparison.OrdinalIgnoreCase));

            if (node == null) return resultList.ToArray();

            // 完整路径
            var fullPath = Path.Combine(_slnDir, node.ReleativePath);

            var stra = node.Strategy;
            if (stra == null) return resultList.ToArray();

            // 获得所有匹配的路径。
            var matchedPaths = stra.GetMatchedPaths(fullPath);

            var fileId = identifier.FileId;
            var memberId = identifier.MemberId;


            foreach (var matchedPath in matchedPaths)
            {
                var metaData = stra.GetCodeMetaData(matchedPath, fileId, memberId);
                if (metaData != null)
                {
                    resultList.Add(metaData);
                }
            }

            return resultList.ToArray();
        }

        ///<summary>获得当前层级点的Id/Name</summary>
        public string GetNodeId(string filePath)
        {
            foreach (var nodePair in _sortedNodePairs)
            {
                var prefix = nodePair.FullPath;
                if (filePath.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) return nodePair.Name;
            }

            return string.Empty;
            //_config.Nodes.OrderByDescending(n => n.ReleativePath);
        }

        ///<summary>获得节点的Id。</summary>
        public ToyNode GetNodeById(string nodeId)
        {
            return _config.Nodes
                .FirstOrDefault(i => string.Equals(i.Name, nodeId, StringComparison.OrdinalIgnoreCase));
        }

        #endregion

        #region check methods

        private void CheckSln(string slnPath)
        {
            if (string.IsNullOrWhiteSpace(slnPath)) throw new ArgumentNullException("DiectoryManager.CheckSln: 目录管理器需要提供一个明确的 sln 的文件的路径");
            if (File.Exists(slnPath) == false) throw new FileNotFoundException($"DiectoryManager.CheckSln: 无法找到 {slnPath}");
        }

        #endregion

        #region overrides

        public override string ToString()
        {
            var sb = new StringBuilder();

            foreach (var node in _config.Nodes)
            {
                sb.AppendLine(node.Name);
            }
            return sb.ToString();
        }

        #endregion
    }
}
